home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Nebula 2
/
Nebula Two.iso
/
SourceCode
/
GameKit
/
gamekit-1
/
GKActor.m
< prev
next >
Wrap
Text File
|
1995-06-12
|
6KB
|
193 lines
// Handles moving and rendering various moving objects.
#import <gamekit/gamekit.h>
#import <stdio.h>
@implementation GKActor
- init // initialize the new instance vars
{ // You need to override this to set state and maxFrames at the very least
[super init];
NX_X(&boundingBox) = 0;
NX_Y(&boundingBox) = 0;
NX_HEIGHT(&boundingBox) = GK_DEFAULT_ACTOR_WIDTH;
NX_WIDTH(&boundingBox) = GK_DEFAULT_ACTOR_HEIGHT;
GK_CLEAR_VECTOR(&nextLocation);
GK_CLEAR_VECTOR(&lastLocation);
GK_CLEAR_VECTOR(&lastDrawnLocation);
maxFrames = (int *)malloc(sizeof(int));
maxFrames[0] = 0; maxSeries = 1; series = 0;
frame = 0; cycles = 0; state = GK_DEAD_ACTOR;
renderedImage = nil; drawingLevel = GK_DYNAMIC_ACTOR;
return self;
}
- (int)drawingLevel { return drawingLevel; }
- setDrawingLevel:(int)aLevel { drawingLevel = aLevel; return self; }
- stage { return stage; }
- setStage:aStage { // ***** probably ought to make sure we're not on any other stage!
stage = aStage;
return self;
}
- leaveTheStage
{
[stage removeActor:self ofType:drawingLevel];
return self;
}
- setSize:(const NXSize *)aSize
// set the actor's size (enclosing frame in image)
{
GK_COPY_SIZES(&(boundingBox.size), aSize);
return self;
}
- setRenderedImage:anImage // set the bitmap image used to render
{ // we don't free an old image, if it exists. This is because others
// might also be using the image. What I should do is a reference
// counting image *****
renderedImage = anImage;
return self;
}
- setSeries:(int)anInt // set the animation series (row) to use in bitmap
{
if (anInt >= maxSeries) return nil; // only change to a valid series number
series = anInt;
return self;
}
- setMaxFrames:(const int *)anIntArray count:(int)anInt // array indexed by
// series number; gives the number of frames in the series
{ // This could possibly be incorporated into an "Array" object, perhaps
// one which does reference counting. *****
int i;
free(maxFrames); maxFrames = (int *)malloc(sizeof(int) * anInt);
for (i=0; i<anInt; i++) maxFrames[i] = anIntArray[i];
maxSeries = anInt;
return self;
}
- move:sender // Move the Actor one animation frame
{ // you must override this and put something here
// alter the nextLocation vector to move the actor.
return self;
}
- (int)collisionType // called to determine which type of collision
// detection to use with this actor
{ // override to change type... default is the bounding box
return GK_RECTANGLE_SHAPE;
}
- (void *)shapeStruct // if you change the collision type, you must
{ // return a pointer to an appropriate structure defining the shape
return (&boundingBox); // Note that if you call this method, do NOT
// alter the boundingBox returned! It will cause all sorts of havoc!
}
- collidedWith:anActor // called when it is detected that we hit something
{ // you should override to do something about the hit, if necessary
return self;
}
- lastAt:(NXPoint *)aPoint // called to find out where actor was
{
GK_COPY_VECTORS(aPoint, &lastLocation);
return self;
}
- lastDrawnAt:(NXPoint *)aPoint // called to find out where actor was
{
GK_COPY_VECTORS(aPoint, &lastDrawnLocation);
return self;
}
- at:(NXPoint *)aPoint // called to find out where actor was
{
GK_COPY_VECTORS(aPoint, &GK_location);
return self;
}
- getBoundingBox:(NXRect *)box
{
GK_COPY_RECT(box, &boundingBox);
return self;
}
- (int)series { return series; } // the series we're currently using
- (int)frame { return frame; } // the next frame that will be drawn
- moveOneFrame // moves the actor along; accessed via renderAt::move:
{
// flag movement; we won't redraw if no movement...
if ((GK_VECTOR_X(&GK_location) != GK_VECTOR_X(&nextLocation)) ||
(GK_VECTOR_Y(&GK_location) != GK_VECTOR_Y(&nextLocation)))
movedThisFrame = YES;
GK_COPY_VECTORS(&GK_location, &nextLocation);
GK_COPY_VECTORS(&lastLocation, &GK_location);
return self;
}
- eraseInDirtPile:dirtPile
{ // pass our most recent dirty rect to the DirtPile...
[dirtPile addRegion:GK_VECTOR_X(&lastDrawnLocation)
:GK_VECTOR_Y(&lastDrawnLocation)
:boundingBox.size.width
:boundingBox.size.height];
return self;
}
- markInDirtPile:dirtPile // same as above but called at different times
{ // pass our most recent dirty rect to the DirtPile...
[dirtPile addRegion:GK_VECTOR_X(&lastDrawnLocation)
:GK_VECTOR_Y(&lastDrawnLocation)
:boundingBox.size.width
:boundingBox.size.height];
return self;
}
- renderAt:(NXPoint *)offset move:(BOOL)moveOk withDirtPile:dirtPile
// draw actor; lock focus on view that gets the actor before call
{ // this should be overridden by the actor subclass
NXPoint zero = { 0.0, 0.0 };
if (state == GK_DEAD_ACTOR) return self; // we're dead, nothing to do
if (moveOk) [self moveOneFrame];
GK_COPY_VECTORS(&lastDrawnLocation, &GK_location); // we need to track
// this so we can do erase properly
if (movedThisFrame) { // handle the drawing if need to redraw.
if (offset) [self drawActorWithOffset:offset];
else [self drawActorWithOffset:&zero];
// mark the drawn area as dirty
[self markInDirtPile:dirtPile];
movedThisFrame = NO;
}
[self updateDrawingState]; // we update _even_ if no movement;
// if you object is stationary, but changes shape a lot, then
// you should set the movedThisFrame flag in this method!
return self;
}
- drawActorWithOffset:(NXPoint *)offset // draw the actor
{ // 90% of the time you'll override this completely
NXRect from = { { frame * NX_WIDTH(&boundingBox),
series * NX_HEIGHT(&boundingBox) },
{ NX_WIDTH(&boundingBox), NX_HEIGHT(&boundingBox) } };
NXPoint pos = { NX_X(&boundingBox) + GK_VECTOR_X(offset),
NX_Y(&boundingBox) + GK_VECTOR_Y(offset) };
[renderedImage composite:NX_SOVER fromRect:&from toPoint:&pos];
return self;
}
- updateDrawingState // change the internal state machine (ie. advance
{ // frames, etc. This will also
cycles++;
frame++; if (frame >= maxFrames[series]) frame = 0;
return self;
}
@end